package utilities;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import javax.xml.XMLConstants;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.exist.xmldb.DatabaseInstanceManager;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.CollectionManagementService;

/**
 *
 * @author Hacnar
 */
public class DBUtils {

    private static String URI = "xmldb:exist:///db";
    
    public static void openDBConnection() {
        final String driver = "org.exist.xmldb.DatabaseImpl";
        
        // initialize database driver
        Class cl = null;
        try {
            cl = Class.forName(driver);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
        }
        Database database = null;
        try {
            database = (Database) cl.newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
        }
        try {
            database.setProperty("create-database", "true");
            DatabaseManager.registerDatabase(database);
        } catch (XMLDBException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
        }
    }
    
    public static void closeDB() {
        DatabaseInstanceManager manager; 
        try {
            Collection col = DatabaseManager.getCollection("xmldb:exist:///db", "admin", "");
            manager = (DatabaseInstanceManager) col.getService("DatabaseInstanceManager", "1.0");
            manager.shutdown();
        } catch (XMLDBException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
        }
    }
    
    public static boolean validate(String resXML, String xmlSchema) {
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

        Schema schema = null;
        try {
            schema = factory.newSchema(new StreamSource(DBUtils.class.getClassLoader().getResourceAsStream(xmlSchema)));
        } catch (SAXException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
            System.out.println(ex.getCause()+ex.getMessage());
        }

        Validator validator = schema.newValidator();

        try {
            validator.validate(new SAXSource(new InputSource(new StringReader(resXML))));
        } catch (SAXException e) {
            return false;
        } catch (IOException ex) {
            Logger.getLogger(DBUtils.class.getName()).log(Level.ERROR, null, ex);
        }
        return true;
    }
    
    public static Collection getOrCreateCollection(String collectionUri) throws XMLDBException {
        return getOrCreateCollection(collectionUri, 0);
    }
    
    public static Collection getOrCreateCollection(String collectionUri, int pathSegmentOffset) throws XMLDBException {
        
        Collection col = DatabaseManager.getCollection(URI + collectionUri);
        if(col == null) {
            if(collectionUri.startsWith("/")) {
                collectionUri = collectionUri.substring(1);
            }

            String pathSegments[] = collectionUri.split("/");
            if(pathSegments.length > 0) {

                StringBuilder path = new StringBuilder();
                for(int i = 0; i <= pathSegmentOffset; i++) {
                    path.append("/").append(pathSegments[i]);
                }

                Collection start = DatabaseManager.getCollection(URI + path);
                if(start == null) {
                    String parentPath = path.substring(0, path.lastIndexOf("/"));
                    Collection parent = DatabaseManager.getCollection(URI + parentPath);
                    CollectionManagementService mgt = (CollectionManagementService) parent.getService("CollectionManagementService", "1.0");
                    col = mgt.createCollection(pathSegments[pathSegmentOffset]);
                    col.close();
                    parent.close();
                } else {
                    start.close();
                }
            }
            return getOrCreateCollection("/"+collectionUri, ++pathSegmentOffset);
        } else {
            return col;
        }
    }
}
